存储耗尽
自由存储运算符new、delete、new[]和delete[]通过一些在头文件<new>
里描述的函数实现(19.4.5节):
void* operator new(size_t); // 为单个对象分配空间
void operator delete(void*);
void* operator new[](size_t); // 为数组分配空间
void operator delete[](void*);
当运算符new需要为某个对象分配空间时,它将调用operator new()去分配适当数量的字节。与此类似,当运算符new需要为一个数组分配空间时,就去调用operator new。
operator new()和operator new的标准实现并不对返回的存储做初始化。
当new无法找到需要分配的空间时会发生什么情况呢?按照默认方式,这个分配函数将抛出一个bad_alloc异常(另一种情况见19.4.5节)。例如,
void f()
{
try {
for(;;) new char[10000];
}
catch(bad_alloc) {
cerr << "Memory exhausted!\n";
}
}
无论我们能用的空间有多少,这一程序最终都会激活bad_alloc处理器。
我们可以规定在存储耗尽时new应该去做什么。当new失败时,它将先去调用一个函数(如果存在),该函数是通过调用在 <new>
里声明的set_new_handler()设定的。例如,
void out_of_store()
{
cerr << "operator new failed: out of store\n";
throw bad_alloc();
}
int main()
{
set_new_handler(out_of_store); // 将out_of_store()作为新的处理函数
for(;;) new char[10000];
cout << "done\n";
}
这个程序不会到达写出done的地方。它将写出
operator new failed: out of store
參看14.4.5节关于operator new()的可能实现情况,它检查是否存在着能调用的处理函数,如果没有就抛出bad_alloc。new_hander有可能做出某些比简单地终止程序更聪明的事情。如果你知道new和delete是如何工作的---例如因为你提供了自己的operator new()和operator delete(),这个处理函数可能是企图去为new找到另一些存储并返回之。另一种方式是,某个用户可能提供一个废料收集器,使得delete的使用变成选择性的。当然,做这些事情都不是一个初学者的工作。对于所有需要自动废料收集器的人而言,应该做的正确事情是去获得一个已经写好并经过仔细测试的程序(C.9.1节)。
通过提供new_handler,我们就处理了在程序中所有new的常规使用中对存储耗尽情况的检查。也存在另外两种控制存储分配的替代方法。我们可以为new的非标准使用提供非标准的分配函数和释放函数(15.6节),或者是依靠用户提供有关存储分配的附加信息(10.4.11节、19.4.5节)。
🔚